home *** CD-ROM | disk | FTP | other *** search
/ Programming an RTS Game with Direct3D / Programming an RTS Game with Direct3D.iso / Examples / Chapter 5 / Example 5.10 / camera.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2006-07-17  |  6.9 KB  |  263 lines

  1. #include "camera.h"
  2.  
  3. CAMERA::CAMERA()
  4. {
  5.     Init(NULL);
  6. }
  7.  
  8. void CAMERA::Init(IDirect3DDevice9* Dev)
  9. {
  10.     m_pDevice = Dev;
  11.     m_alpha = m_beta = 0.5f;
  12.     m_radius = 10.0f;
  13.     m_fov = D3DX_PI / 4.0f;
  14.  
  15.     m_eye = D3DXVECTOR3(50.0f, 50.0f, 50.0f);
  16.     m_focus = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
  17. }
  18.  
  19. void CAMERA::Scroll(D3DXVECTOR3 vec)
  20. {
  21.     D3DXVECTOR3 newFocus = m_focus + vec;
  22.    m_focus = newFocus;
  23. }
  24.  
  25. void CAMERA::Pitch(float f)
  26. {
  27.     m_beta += f;
  28.  
  29.     if(m_beta > (D3DX_PI / 2.0f) - 0.05f)m_beta = D3DX_PI / 2.0f - 0.05f;
  30.     if(m_beta < 0.5f)m_beta = 0.5f;
  31. }
  32.  
  33. void CAMERA::Yaw(float f)
  34. {
  35.     m_alpha += f;
  36.     if(m_alpha > D3DX_PI * 2.0f)m_alpha -= D3DX_PI * 2.0f;
  37.     if(m_alpha < -D3DX_PI * 2.0f)m_alpha += D3DX_PI * 2.0f;
  38. }
  39.  
  40. void CAMERA::Zoom(float f)
  41. {
  42.     m_fov += f;
  43.  
  44.     if(m_fov < 0.1f)m_fov = 0.1f;
  45.     if(m_fov > D3DX_PI / 2.0f)m_fov = D3DX_PI / 2.0f;
  46. }
  47.  
  48. void CAMERA::ChangeRadius(float f)
  49. {
  50.     m_radius += f;
  51.  
  52.     if(m_radius < 2.0f)m_radius = 2.0f;
  53.     if(m_radius > 70.0f)m_radius = 70.0f;
  54. }
  55.  
  56. void CAMERA::Update(MOUSE &mouse, TERRAIN &terrain, float timeDelta)
  57. {
  58.     //Restrict focus movment to the xz-plane
  59.     m_right.y = m_look.y = 0.0f;
  60.     D3DXVec3Normalize(&m_look, &m_look);
  61.     D3DXVec3Normalize(&m_right, &m_right);
  62.  
  63.     //Move Focus (i.e. Scroll)
  64.     if(mouse.x < mouse.m_viewport.left + 10)    Scroll(-m_right * timeDelta * (4.0f + m_radius * 0.2f));
  65.     if(mouse.x > mouse.m_viewport.right - 10)    Scroll(m_right * timeDelta * (4.0f + m_radius * 0.2f));
  66.     if(mouse.y < mouse.m_viewport.top + 10)        Scroll(m_look * timeDelta * (4.0f + m_radius * 0.2f));
  67.     if(mouse.y > mouse.m_viewport.bottom - 10)    Scroll(-m_look * timeDelta * (4.0f + m_radius * 0.2f));
  68.  
  69.     //Move Camera (i.e. Change Angle)
  70.     if(KEYDOWN(VK_LEFT))Yaw(-timeDelta);
  71.     if(KEYDOWN(VK_RIGHT))Yaw(timeDelta);
  72.     if(KEYDOWN(VK_UP))Pitch(timeDelta);
  73.     if(KEYDOWN(VK_DOWN))Pitch(-timeDelta);
  74.     
  75.     //Zoom (i.e. change fov)
  76.     if(KEYDOWN(VK_ADD))Zoom(-timeDelta);
  77.     if(KEYDOWN(VK_SUBTRACT))Zoom(timeDelta);
  78.  
  79.     //Change radius
  80.     if(mouse.WheelUp())  ChangeRadius(-1.0f);
  81.     if(mouse.WheelDown())ChangeRadius(1.0f);
  82.  
  83.     //Calculate Eye Position
  84.     float sideRadius = m_radius * cos(m_beta);
  85.     float height = m_radius * sin(m_beta);
  86.  
  87.     m_eye = D3DXVECTOR3(m_focus.x + sideRadius * cos(m_alpha),
  88.                       m_focus.y + height, 
  89.                       m_focus.z + sideRadius * sin(m_alpha));
  90.  
  91.     //Have the focus follow the terrain heights
  92.     //Find patch that the focus is over
  93.     for(int p=0;p<terrain.m_patches.size();p++)
  94.     {
  95.         RECT mr = terrain.m_patches[p]->m_mapRect;
  96.  
  97.         //Focus within patch maprect or not?
  98.         if(m_focus.x >= mr.left && m_focus.x < mr.right &&
  99.              -m_focus.z >= mr.top && -m_focus.z < mr.bottom)
  100.         {            
  101.             // Collect only the closest intersection
  102.             BOOL hit;
  103.             DWORD dwFace;
  104.             float hitU, hitV, dist;
  105.             D3DXIntersect(terrain.m_patches[p]->m_pMesh, &D3DXVECTOR3(m_focus.x, 10000.0f, m_focus.z), 
  106.                           &D3DXVECTOR3(0.0f, -1.0f, 0.0f), &hit, &dwFace, &hitU, &hitV, 
  107.                           &dist, NULL, NULL);
  108.  
  109.             if(hit)m_focus.y = 10000.0f - dist;
  110.         }
  111.     }
  112.  
  113.     if(m_pDevice != NULL)
  114.     {
  115.         D3DXMATRIX view = GetViewMatrix();
  116.         D3DXMATRIX projection = GetProjectionMatrix();
  117.  
  118.         m_pDevice->SetTransform(D3DTS_VIEW, &view);
  119.         m_pDevice->SetTransform(D3DTS_PROJECTION, &projection);
  120.  
  121.         CalculateFrustum(view, projection);
  122.     }    
  123. }
  124.  
  125. D3DXMATRIX CAMERA::GetViewMatrix()
  126. {
  127.     D3DXMATRIX  matView;
  128.     D3DXMatrixLookAtLH(&matView, &m_eye, &m_focus, &D3DXVECTOR3(0.0f, 1.0f, 0.0f));
  129.  
  130.     m_right.x = matView(0,0);
  131.     m_right.y = matView(1,0);
  132.     m_right.z = matView(2,0);
  133.     D3DXVec3Normalize(&m_right, &m_right);
  134.  
  135.     m_look.x = matView(0,2);
  136.     m_look.y = matView(1,2);
  137.     m_look.z = matView(2,2);
  138.     D3DXVec3Normalize(&m_look, &m_look);
  139.  
  140.     return  matView;
  141. }
  142.  
  143. D3DXMATRIX CAMERA::GetProjectionMatrix()
  144. {
  145.     D3DXMATRIX  matProj;
  146.     float aspect = 800.0f / 600.0f;
  147.     D3DXMatrixPerspectiveFovLH(&matProj, m_fov, aspect, 1.0f, 1000.0f );
  148.     return matProj;
  149. }
  150.  
  151. void CAMERA::CalculateFrustum(D3DXMATRIX view, D3DXMATRIX projection)
  152. {
  153.     try
  154.     {
  155.         // Get combined matrix
  156.         D3DXMATRIX matComb;
  157.         D3DXMatrixMultiply(&matComb, &view, &projection);
  158.  
  159.         // Left clipping plane
  160.         m_frustum[0].a = matComb._14 + matComb._11; 
  161.         m_frustum[0].b = matComb._24 + matComb._21; 
  162.         m_frustum[0].c = matComb._34 + matComb._31; 
  163.         m_frustum[0].d = matComb._44 + matComb._41;
  164.  
  165.         // Right clipping plane 
  166.         m_frustum[1].a = matComb._14 - matComb._11; 
  167.         m_frustum[1].b = matComb._24 - matComb._21; 
  168.         m_frustum[1].c = matComb._34 - matComb._31; 
  169.         m_frustum[1].d = matComb._44 - matComb._41;
  170.  
  171.         // Top clipping plane 
  172.         m_frustum[2].a = matComb._14 - matComb._12; 
  173.         m_frustum[2].b = matComb._24 - matComb._22; 
  174.         m_frustum[2].c = matComb._34 - matComb._32; 
  175.         m_frustum[2].d = matComb._44 - matComb._42;
  176.  
  177.         // Bottom clipping plane 
  178.         m_frustum[3].a = matComb._14 + matComb._12; 
  179.         m_frustum[3].b = matComb._24 + matComb._22; 
  180.         m_frustum[3].c = matComb._34 + matComb._32; 
  181.         m_frustum[3].d = matComb._44 + matComb._42;
  182.  
  183.         // Near clipping plane 
  184.         m_frustum[4].a = matComb._13; 
  185.         m_frustum[4].b = matComb._23; 
  186.         m_frustum[4].c = matComb._33; 
  187.         m_frustum[4].d = matComb._43;
  188.  
  189.         // Far clipping plane 
  190.         m_frustum[5].a = matComb._14 - matComb._13; 
  191.         m_frustum[5].b = matComb._24 - matComb._23; 
  192.         m_frustum[5].c = matComb._34 - matComb._33; 
  193.         m_frustum[5].d = matComb._44 - matComb._43; 
  194.  
  195.         //Normalize planes
  196.         for(int i=0;i<6;i++)
  197.             D3DXPlaneNormalize(&m_frustum[i], &m_frustum[i]);
  198.     }
  199.     catch(...)
  200.     {
  201.         debug.Print("Error in CAMERA::CalculateFrustum()");
  202.     }
  203. }
  204.  
  205. bool CAMERA::Cull(BBOX bBox)
  206. {
  207.     try
  208.     {
  209.         //For each plane in the view frustum
  210.         for(int f=0;f<6;f++)
  211.         {
  212.             D3DXVECTOR3 c1, c2;
  213.  
  214.             //Find furthest point (n1) & nearest point (n2) to the plane
  215.             if(m_frustum[f].a > 0.0f)    {c1.x = bBox.max.x; c2.x = bBox.min.x;}
  216.             else                    {c1.x = bBox.min.x; c2.x = bBox.max.x;}
  217.             if(m_frustum[f].b > 0.0f)    {c1.y = bBox.max.y; c2.y = bBox.min.y;}
  218.             else                    {c1.y = bBox.min.y; c2.y = bBox.max.y;}
  219.             if(m_frustum[f].c > 0.0f)    {c1.z = bBox.max.z; c2.z = bBox.min.z;}
  220.             else                    {c1.z = bBox.min.z; c2.z = bBox.max.z;}
  221.  
  222.             float distance1 = m_frustum[f].a * c1.x + m_frustum[f].b * c1.y + 
  223.                               m_frustum[f].c * c1.z + m_frustum[f].d;
  224.             float distance2 = m_frustum[f].a * c2.x + m_frustum[f].b * c2.y + 
  225.                               m_frustum[f].c * c2.z + m_frustum[f].d;
  226.  
  227.             //If both points are on the negative side of the plane, Cull!
  228.             if(distance1 < 0.0f && distance2 < 0.0f)
  229.                 return true;
  230.         }
  231.  
  232.         //Object is inside the volume
  233.         return false;
  234.     }
  235.     catch(...)
  236.     {
  237.         debug.Print("Error in CAMERA::Cull()");
  238.         return true;
  239.     }
  240. }
  241.  
  242. bool CAMERA::Cull(BSPHERE bSphere)
  243. {
  244.     try
  245.     {
  246.         //For each plane in the view frustum
  247.         for(int f=0;f<6;f++)
  248.         {
  249.             float distance = D3DXVec3Dot(&bSphere.center, &D3DXVECTOR3(m_frustum[f].a, m_frustum[f].b, m_frustum[f].c)) + m_frustum[f].d;
  250.  
  251.             if(distance < -bSphere.radius)
  252.                 return true;
  253.         }
  254.  
  255.         //Object is inside the volume
  256.         return false;
  257.     }
  258.     catch(...)
  259.     {
  260.         debug.Print("Error in CAMERA::Cull()");
  261.         return true;
  262.     }
  263. }